
package com.scs.application.modules.base.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.scs.application.core.exceptions.BusinessException;
import com.scs.application.core.service.TreeServiceImpl;
import com.scs.application.core.utils.BeanUtils;
import com.scs.application.core.utils.StringUtils;
import com.scs.application.core.utils.UserUtils;
import com.scs.application.modules.base.entity.HospitalCatalog;
import com.scs.application.modules.base.mapper.HospitalCatalogMapper;
import com.scs.application.modules.base.request.HospitalCatalogQueryRequest;
import com.scs.application.modules.base.service.HospitalCatalogService;
import com.scs.application.modules.base.vo.HCatalogVO;
import com.scs.application.modules.base.vo.HospitalCatalogVO;
import com.scs.application.modules.thirdparty.dto.HospitalCatalogDTO;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StopWatch;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 医院品类 service 实现
 */
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class HospitalCatalogServiceImpl extends TreeServiceImpl<HospitalCatalogMapper, HospitalCatalog> implements HospitalCatalogService {
    @Override
    public List<HospitalCatalog> list(HospitalCatalogQueryRequest request) {
        request.setHospitalId(UserUtils.getHospitalId());
        List<HospitalCatalog> list = this.list(Wrappers.<HospitalCatalog>query()
                .eq(request.getMaterialTypeCode() != null, "material_type_code", request.getMaterialTypeCode())
                .eq(request.getHospitalId() != null, "hospital_id", request.getHospitalId())
                .like(StringUtils.isNotBlank(request.getCode()), "code", request.getCode())
                .like(StringUtils.isNotBlank(request.getName()), "name", request.getName())
                .orderByAsc("sort")
        );
        return list;
    }

    @Override
    public IPage<HospitalCatalogVO> page(HospitalCatalogQueryRequest request) {
        request.setHospitalId(UserUtils.getHospitalId());
        return this.baseMapper.page(request.getPage(), request);
    }

    @Override
    public List<HCatalogVO> listForVO() {
        List<HospitalCatalog> list = this.list(Wrappers.<HospitalCatalog>query()
                .select("id","code","name","parent_id")
                .eq("hospital_id", UserUtils.getHospitalId()));
        return BeanUtils.copyProperties(list, HCatalogVO.class);
    }

    @Override
    public List<HCatalogVO> saveDTO(List<HospitalCatalogDTO> dtos) {
        log.info("==============医院品类批量保存开始=================");
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        int insertSize = 0;
        int updateSize = 0;
        String hospitalId = UserUtils.getHospitalId();

        //查询所有品类
        List<HospitalCatalog> catalogList = this.list( Wrappers.<HospitalCatalog>query().select("id,code,name,parent_id").eq("hospital_id",hospitalId));

        //所有pCode集合
        List<String> pCodeList = dtos.stream().map(HospitalCatalogDTO::getPCode).collect(Collectors.toList());
        //所有code集合
        List<String> codeList = dtos.stream().map(HospitalCatalogDTO::getCode).collect(Collectors.toList());
        pCodeList.removeAll(codeList);
        //所有dbCode集合
        List<String> dbCodeList = catalogList.stream().map(HospitalCatalog::getCode).collect(Collectors.toList());
        pCodeList.removeAll(dbCodeList);

        /*if(!pCodeList.isEmpty()){
            throw new BusinessException("上传的品类中有pCode（父级品类代码）还没上传");
        }*/

        /**
         *  院内品类 key Code ， value HospitalCatalog
         */
        Map<String, HospitalCatalog> hospitalMap = catalogList.stream().collect(Collectors.toMap(o -> o.getCode(), o -> o, (o1, o2) -> o1));
        log.info("加载到{}条医院品类数据", hospitalMap.size());

        ArrayList<HCatalogVO> result = Lists.newArrayList();    //Lists.newArrayListWithExpectedSize(grCodecount);
        /**
         *
         A           --- 第1次循环插入
         B         C       --- 第2次循环插入
         D E F         G H I   --- 第3次循环插入
         D1 E1 F1                --- ...
         */
        // 将提交的品类，按 pcode 分组，以自然顺序排列
        Map<String, List<HospitalCatalogDTO>> dtoSorted = dtos.stream()
                .sorted(Comparator.comparing(HospitalCatalogDTO::getSSort, Comparator.nullsLast(Comparator.naturalOrder())))
                .collect(Collectors.groupingBy(HospitalCatalogDTO::getPCode, LinkedHashMap::new, Collectors.toList()));
        /** 正式开始保存品类 **/
        // pCode 分组循环
        for (Map.Entry<String, List<HospitalCatalogDTO>> elem : dtoSorted.entrySet()){

            String pCode = elem.getKey();
            log.debug("pCode : "+ pCode);
            log.debug("list : "+ elem.getValue());
            // pCode子集循环
            for (HospitalCatalogDTO dto : elem.getValue()) {

                HospitalCatalog hc = new HospitalCatalog();
                hc.setCode(dto.getCode());
                hc.setHospitalId(hospitalId);
                hc.setName(dto.getName());
                hc.setFullName(dto.getFullName());

                // 获取首营平台父级品类
                HospitalCatalog pId = hospitalMap.get(dto.getPCode());
                if (pId == null) {
                    // Pcode = 0 直接指向顶级
                    if ("0".equals(dto.getPCode())) {
                        hc.setParentId("0");
                    } else {
                        // 获取不到父级品类，终止整个子集的遍历
                        break;
                    }
                } else {
                    // 有，设置当前parentId
                    hc.setParentId(pId.getId());
                }

                Map<String, HospitalCatalog> map = hospitalMap.values().stream().collect(Collectors.toMap(o -> o.getId(), o -> o, (o1, o2) -> o1));
                // 设置parentids 默认0
                String parentIds = ",0,";
                if (!"0".equals(hc.getParentId())){
                    // 非顶级节点需要构建parentIds
                    parentIds = buildParentIds(map, hc.getParentId(), hc.getParentId());
                }

                if(StringUtils.isBlank(parentIds)){
                    throw new BusinessException("查找品类关系失败！");
                }
                hc.setParentIds(parentIds);
                hc.setSort(Long.valueOf(hc.getLevel()));

                // 获取品类代码 的 id
                HospitalCatalog Id = hospitalMap.get(hc.getCode());
                // 是否新品类
                if (Id ==null) {
                    this.save(hc);
                    // 补充新增提交的 code 和 id；
                    hospitalMap.put(hc.getCode(), hc);
                    insertSize++;
                }else{
                    hc.setId(Id.getId());
                    this.updateById(hc);
                    updateSize++;
                }
                HCatalogVO resultVo = new HCatalogVO();
                resultVo.setId(hc.getId());
                resultVo.setCode(hc.getCode());
                result.add(resultVo);
            }
        }
        stopWatch.stop();
        log.info("医院品类：新增{}条, 更新{}条", insertSize, updateSize);

        return result;
    }

    /**
     * 在集合里查找并构建 parentIds
     * @param hospitalMap 医院全部品类 key 品类id  value 品类
     * @param parentId
     * @return
     */
    private String buildParentIds(Map<String, HospitalCatalog> hospitalMap, String parentId, String parentIds){

        // 如果 hospitalMap 有 id 的对象
        HospitalCatalog hc = hospitalMap.get(parentId);
        if (hc == null) {
            // 找不到？ "那我走"
            return ",0," + parentIds + ",";
        }
        // 找到它
        String id = hc.getParentId();
        // 并且追加
        if ("0".equals(id)) {
            // 到头了？ "那我走"
            return ",0," + parentIds + ",";
        }else{
            // 还有，我就继续找
            parentIds = id+","+parentIds;
            return buildParentIds(hospitalMap, id, parentIds);
        }

    }
}
